/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.server.grpc.interceptor;

import io.grpc.*;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.core.session.CafSession;
import io.iec.edp.caf.core.session.ICafSessionService;
import io.iec.edp.caf.rpc.api.grpc.annotation.GrpcServerInterceptor;
import io.iec.edp.caf.rpc.api.grpc.variable.GrpcVariable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;

@Slf4j
@GrpcServerInterceptor
public class CafGrpcServerInterceptor implements ServerInterceptor {

    private static final ICafSessionService css = SpringBeanUtils.getBean(ICafSessionService.class);

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        //请求开始 还原session
        String sessionId = headers.get(GrpcVariable.SESSION_ID);
        String sessionStr = headers.get(GrpcVariable.SESSION);
        //认证失败
        if(sessionId==null||sessionStr==null){
            call.close(Status.CANCELLED.withDescription("gRpc 401 Unauthorized. There's no session information."),headers);
            //throw new StatusException(Status.CANCELLED.withDescription("gRpc 401 Unauthorized. There's no session information."));
            throw new SecurityException("gRpc 401 Unauthorized. There's no session information.");
        }
        //CafSession cafSession = JSONSerializer.deserialize(sessionStr,CafSession.class);
        CafSession cafSession = css.findById(sessionId);
        if(cafSession==null){
            call.close(Status.CANCELLED.withDescription("gRpc 401 Unauthorized. Can't recognize session information."),headers);
            //throw new StatusException(Status.CANCELLED.withDescription("gRpc 401 Unauthorized. Can't recognize session information."));
            throw new SecurityException("gRpc 401 Unauthorized. Can't recognize session information.");
        }
        log.info("Grpc set sessionId: "+sessionId);
        //还原至security上下文
        SecurityContextHolder.getContext().setAuthentication(cafSession);
        //log.error(token);
        //服务端写回参数
        ServerCall<ReqT, RespT> serverCall = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {

            @Override
            public void sendHeaders(Metadata headers) {
                super.sendHeaders(headers);
            }
        };
        //执行服务端业务逻辑
        return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(serverCall,headers)) {

            @Override
            public void onMessage(ReqT message) {
                super.onMessage(message);
            }

            /**
             * 请求结束 清理上下文等
             */
            @Override
            public void onComplete() {
                SecurityContextHolder.clearContext();
                super.onComplete();
            }
        };
    }
}
